package com.lckoo.mail.receiver;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 邮件内容解析
 * https://blog.csdn.net/mylovepan/article/details/105977396
 */
@Slf4j
@Getter
@Setter
@ToString
public class MailInfo {
    private MimeMessage mimeMessage = null;
    /**
     * 邮件内容
     */
    private String bodyText = "";
    /**
     * 发件人
     */
    private String from;
    private String to;
    private String cc;
    private String bcc;
    private String subject;
    private Date sentDate;
    private Date receivedDate;
    private String messageID;
    private String box;


    public MailInfo(MimeMessage mimeMessage) {
        this.mimeMessage = mimeMessage;
        parse();
        log.debug("创建一个MailParser对象....");
    }

    /**
     * 解析邮件的内容
     */
    private void parse() {
        Folder folder = this.mimeMessage.getFolder();
        try {
            if (!folder.isOpen()) {
                return;
//                folder.open(Folder.READ_ONLY);
            }
            this.from = genFrom();
            this.to = address(getMailAddress(EnumRecipientType.TO));
            this.cc = address(getMailAddress(EnumRecipientType.CC));
            this.bcc = address(getMailAddress(EnumRecipientType.BCC));
            this.subject = MimeUtility.decodeText(mimeMessage.getSubject());
            this.sentDate = mimeMessage.getSentDate();
            this.receivedDate = mimeMessage.getReceivedDate();

            // 邮件内容解析开始>>>>>>>存放邮件内容的StringBuffer对象
            StringBuffer bodyTextBuf = new StringBuffer();
            Map<String, String> imgs = new HashMap<String, String>();
            getMailContent(bodyTextBuf, imgs, this.mimeMessage);
            String tmpContent = bodyTextBuf.toString();
            //替换原文中的图片，原始图片标签为<img src="cid:image001.jpg@01D24963.3B4B8280">
            for (String contentId : imgs.keySet()) {
                String replacedText = "cid:" + contentId.replace("<", "").replace(">", "");
                tmpContent = tmpContent.replace(replacedText, imgs.get(contentId));
            }
            bodyText = tmpContent;
            // <<<<<<<<邮件内容解析结束
            this.messageID = mimeMessage.getMessageID();
            this.box = mimeMessage.getFolder().getName();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
//            try {
//                folder.close(false);
//            } catch (MessagingException e) {
//                e.printStackTrace();
//            }
        }
    }

    public static String address(String personaddress) {
        if (StringUtils.isEmpty(personaddress)) {
            return "";
        }
        String regex = ".*<(.*)>.*";
        Pattern p = Pattern.compile(regex);
        List<String> list = new ArrayList<String>();
        for (String pa : personaddress.split(";")) {
            Matcher matcher = p.matcher(pa);
            if (matcher.matches()) {
                String addr = matcher.group(1);
                list.add(addr);
            }
        }
        return StringUtils.join(list.toArray(new String[0]), ";");
    }

    public String genFrom() throws MessagingException {
        InternetAddress address[] = (InternetAddress[]) mimeMessage.getFrom();
        String from = address[0].getAddress();
        if (from == null) {
            from = "";
            log.warn("发送人邮箱地址为空!");
        }
        return from;
    }

    /**
     * 　*　获得发件人的地址和姓名 　
     *
     */
    public String getFrom() {
        return from;
    }

    /**
     * 收件人
     *
     * @return
     */
    public String getTo() {
        return this.to;
    }

    /**
     * 抄送人
     *
     * @return
     */
    public String getCc() {
        return this.cc;
    }

    /**
     * 私密抄送
     *
     * @return
     */
    public String getBcc() {
        return this.bcc;
    }

    /**
     * <p>
     * 获得邮件的收件人，抄送，和密送的地址和姓名，根据所传递的参数的不同
     * </p>
     *
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private String getMailAddress(EnumRecipientType type) throws MessagingException, UnsupportedEncodingException {
        String mailAddr = "";
        InternetAddress[] address = null;
        switch (type) {
            case TO:
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.TO);
                break;
            case CC:
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.CC);
                break;
            case BCC:
                address = (InternetAddress[]) mimeMessage.getRecipients(Message.RecipientType.BCC);
                break;
        }
        if (address != null) {
            String[] addrs = new String[address.length];
            int i = 0;
            for (InternetAddress addr : address) {
                String emailAddr = MimeUtility.decodeText(addr.getAddress());
                String personal = MimeUtility.decodeText(addr.getPersonal());
                addrs[i++] = personal + "<" + emailAddr + ">";
            }
            mailAddr = StringUtils.join(addrs, ",");
        }
        return mailAddr;
    }

    /**
     * 获得邮件主题 　
     *
     */
    public String getSubject() {
        return this.subject;
    }

    /**
     * 邮件发送日期 　
     *
     * @return
     */
    public Date getSentDate() {
        return this.sentDate;
    }

    /**
     * 邮件接收日期
     *
     * @return
     */
    public Date getReceivedDate() {
        return this.receivedDate;
    }

    /**
     * 获得邮件正文内容
     *
     * @return
     */
    public String getBodyText() {
        return bodyText;
    }

    /**
     * <p>
     * 解析邮件
     * </p>
     *
     * <pre>
     *  主要是根据MimeType类型的不同执行不同的操作，一步一步的解析
     *  把得到的邮件内容保存到一个StringBuffer对象中
     * </pre>
     *
     * @throws MessagingException
     * @throws Exception
     */
    public static void getMailContent(StringBuffer sb, Map<String, String> imgs, Part p) throws Exception {
        if (p.isMimeType("text/plain")) {// 检查内容是否为纯文本
            log.warn("skip text plain");
        } else if (p.isMimeType("text/html")) {// 检查内容是否为html
            sb.append(p.getContent());
        } else if (p.isMimeType("multipart/*")) {// 检查内容是否含有附件
            Multipart mp = (Multipart) p.getContent();
            int count = mp.getCount();
            for (int i = 0; i < count; i++) {
                getMailContent(sb, imgs, mp.getBodyPart(i));
            }
        } else if (p.isMimeType("message/rfc822")) {// 检查内容是否含有嵌套消息
            getMailContent(sb, imgs, (Part) p.getContent());
        } else if (p.isMimeType("image/*")) {// 检查内容是否为内嵌图片
            Object content = p.getContent();
            String contentID = ((String[]) p.getHeader("Content-ID"))[0];
            InputStream in = (InputStream) content;
            byte[] bArray = new byte[in.available()];
            while (((InputStream) in).available() > 0) {
                int result = (int) (((InputStream) in).read(bArray));
                if (result == -1) {
                    break;
                }
            }
            in.close();
            // 文件下载开始
            int i = imgs.size();
            String fileName = "/tmp/" + i + ".jpg";
            FileOutputStream f2 = new FileOutputStream(fileName);
            f2.write(bArray);
            f2.close();
            in.close();
            imgs.put(contentID, fileName);
            // 文件下载结束
        } else {
            log.warn("This is an unknown type:" + p.getContentType());
        }
    }

    /**
     * 　获得此邮件的Message-ID 　　
     */
    public String getMessageId() {
        return this.messageID;
    }

    public String getBox() {
        return this.box;
    }

    public void printHeaders() {
        try {
            Enumeration<Header> allHeaders = mimeMessage.getAllHeaders();
            while (allHeaders.hasMoreElements()) {
                Header header = allHeaders.nextElement();
                System.out.println(header.getName() + "-->" + header.getValue());
            }

        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }

}
